/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package earthdawnnet.util;

import java.util.Random;

/**
 *
 * @author Andreas Franek
 */
public class DiceCup
{

    private static Random random = new Random();
    private static int[] bad =
    {
        0, 0, 1, 1, 1, 1, 2, 2, 4, 5, 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 13, 13, 14, 15, 16, 17, 18, 18, 18, 20, 21, 22, 23, 23, 24, 25, 26, 26, 27, 28, 29, 30, 31, 32, 32, 33, 34, 35, 36, 37
    };
    private static int[] good =
    {
        4, 5, 6, 7, 9, 10, 12, 13, 14, 15, 17, 18, 20, 21, 22, 24, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 36, 38, 40, 40, 41, 42, 43, 45, 46, 47, 48, 50, 51, 52, 53, 54, 55, 56, 58, 59, 60, 61, 62, 63
    };
    private static int[] excellent =
    {
        6, 7, 8, 10, 11, 13, 15, 16, 18, 19, 21, 22, 24, 26, 27, 29, 30, 32, 33, 34, 35, 37, 38, 40, 41, 42, 43, 45, 47, 47, 48, 49, 51, 53, 53, 55, 56, 58, 59, 60, 61, 62, 64, 65, 67, 68, 68, 70, 71, 72
    };
    private static int[] exceptional =
    {
        7, 8, 10, 12, 14, 17, 19, 20, 22, 24, 26, 27, 29, 32, 33, 35, 37, 38, 39, 41, 42, 44, 45, 47, 48, 49, 51, 52, 54, 55, 56, 58, 59, 62, 62, 64, 65, 67, 68, 70, 71, 72, 73, 75, 78, 78, 79, 79, 81, 83
    };
    private static int[][] dice = new int[][]
    {
        {
            4, -2
        },
        {
            4, -1
        },
        {
            4
        },
        {
            6
        },
        {
            8
        },
        {
            10
        },
        {
            12
        },
        {
            6, 6
        },
        {
            8, 6
        },
        {
            10, 6
        },
        {
            10, 8
        },
        {
            10, 10
        },
        {
            12, 10
        },
        {
            20, 4
        },
        {
            20, 6
        },
        {
            20, 8
        },
        {
            20, 10
        },
        {
            20, 12
        },
        {
            20, 6, 6
        },
        {
            20, 8, 6
        },
        {
            20, 10, 6
        },
        {
            20, 10, 8
        },
        {
            20, 10, 10
        },
        {
            20, 12, 10
        },
        {
            20, 10, 8, 4
        },
        {
            20, 10, 8, 6
        },
        {
            20, 10, 8, 8
        },
        {
            20, 10, 10, 8
        },
        {
            20, 12, 10, 8
        },
        {
            20, 10, 8, 6, 6
        },
        {
            20, 10, 8, 8, 6
        },
        {
            20, 10, 10, 8, 6
        },
        {
            20, 10, 10, 8, 8
        },
        {
            20, 10, 10, 10, 8
        },
        {
            20, 12, 10, 10, 8
        },
        {
            20, 20, 10, 8, 4
        },
        {
            20, 20, 10, 8, 6
        },
        {
            20, 20, 10, 8, 8
        },
        {
            20, 20, 10, 10, 8
        },
        {
            20, 20, 12, 10, 8
        },
        {
            20, 20, 10, 8, 6, 6
        },
        {
            20, 20, 10, 8, 8, 6
        },
        {
            20, 20, 10, 10, 8, 6
        },
        {
            20, 20, 10, 10, 8, 8
        },
        {
            20, 20, 10, 10, 10, 8
        },
        {
            20, 20, 12, 10, 10, 8
        },
        {
            20, 20, 10, 10, 8, 8, 4
        },
        {
            20, 20, 10, 10, 8, 8, 6
        },
        {
            20, 20, 10, 10, 8, 8, 8
        },
        {
            20, 20, 10, 10, 10, 8, 8
        }
    };
    private static String[] diceDesc = null;

    public static String[] getDiceDesc()
    {
        if (diceDesc == null)
        {
            createDiceDesc();
        }
        return diceDesc;
    }

    private static void createDiceDesc()
    {
        diceDesc = new String[dice.length];
        for (int i = 0; i < dice.length; i++)
        {
            diceDesc[i] = (i + 1) + ": ";
            if (i < 2)
            {
                diceDesc[i] += "W" + dice[i][0] + dice[i][1];
            } else
            {
                for (int j : dice[i])
                {
                    diceDesc[i] += "W" + j + " + ";
                }
                diceDesc[i] = diceDesc[i].substring(0, diceDesc[i].length() - 3);
            }
        }
    }

    public static Roll roll(int step)
    {
        return roll(step, false, 0);
    }

    public static Roll rollAgainst(int step, int against)
    {
        return roll(step, true, against);
    }
    
    

    public static Roll roll(int step, boolean rollAgainst, int against)
    {
        if(!checkStepExists(step))
        {
            throw new IndexOutOfBoundsException("There is no step" + step);
        }
        String message = "rolled Step " + step + ":";
        boolean max = true;
        boolean fumble = true;
        int sum = 0;
        int internStep = step - 1;
        int rolled;
        if (internStep < 2)
        {
            int diceRoll;
            while (max)
            {
                diceRoll = rollADice(dice[internStep][0]);
                rolled = diceRoll + dice[internStep][1];
                message += " W" + dice[internStep][0] + dice[internStep][1] + ": " + rolled;
                sum += rolled;
                max = (diceRoll == dice[internStep][0]);
                fumble &= (diceRoll == 1);
                if (max)
                {
                    message += " bonus dice";
                }
            }
        } else
        {
            for (int i = 0; i < dice[internStep].length; i++)
            {
                int eyes = dice[internStep][i];
                max = true;
                while (max)
                {
                    rolled = rollADice(eyes);
                    message += " W" + eyes + ": " + rolled;
                    sum += rolled;
                    max = (rolled == eyes);
                    if (max)
                    {
                        message += " bonus dice";
                    }
                    fumble &= (rolled == 1);
                }
            }
        }
        if (fumble)
        {
            message += " You fumble!";
        }
        message += " Total: " + sum;
        if (rollAgainst)
        {
            int againstStep = against - 1;
            message += " against " + against;
            message += (fumble || (sum < against)) ? " failed" : " passed";
            if (successExists(against))
            {
                if (sum < bad[againstStep])
                {
                    message += " badly";
                } else if (sum >= exceptional[againstStep])
                {
                    message += " exceptionally";
                } else if (sum >= excellent[againstStep])
                {
                    message += " outstandingly";
                } else if (sum >= good[againstStep])
                {
                    message += " well";
                }
            }
            message += "!";
        }
        
        Roll result;
        if(rollAgainst)
            result = new Roll(step, against, sum, message);
        else
            result = new Roll(step, sum, message);
        return result;
    }

    public static int getNumberOfSteps()
    {
        return dice.length;
    }

    private static int rollADice(int eyes)
    {
        return random.nextInt(eyes) + 1;
    }

    private static boolean successExists(int against)
    {
        return (against > 0 && against <= bad.length);
    }

    public static boolean checkStepExists(int step)
    {
        return !(step < 1 || step > dice.length);
    }
}
